package com.duowei.diandan.sql;

import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;

import org.joda.time.LocalDateTime;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * 将对象转换成sql字符串
 * <p>
 * 支持的类型
 * ...
 */
public class SqlHelper {
    private static final String TAG = "SqlHelper";

    /**
     * 生成 INSERT SQL
     *
     * @param t
     * @param <T>
     * @return INSERT SQL
     */
    public static <T> String toInsertSql(T t) {
        Class<?> cls = t.getClass();

        // 提取 TableName
        TableName tableName = t.getClass().getAnnotation(TableName.class);
        String tableNameString;
        if (tableName != null) {
            tableNameString = tableName.name();
        } else {
            tableNameString = cls.getSimpleName();
        }

        // 提取 InsertField
        List<Field> insertFieldList = new ArrayList<>();
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field f : fields) {
            Annotation[] annotations = f.getDeclaredAnnotations();
            for (Annotation a : annotations) {
                if (a.annotationType() == InsertField.class) {
                    insertFieldList.add(f);
                    break;
                }
            }
        }

        List<Item> list = new ArrayList<>();


        for (int i = 0; i < insertFieldList.size(); i++) {
            Field field = insertFieldList.get(i);
            field.setAccessible(true);

            String name = field.getType().getName();

            try {
                Object object = field.get(t);
                Item item = new Item();
                item.key = getColumnName(field);

                if (object == null) {
                    item.value = "null";

                } else if ("java.lang.Float".equals(name)
                        || "java.lang.Integer".equals(name)) {
                    item.value = object.toString();

                } else if ("java.lang.String".equals(name)) {
                    item.value = "'" + field.get(t).toString() + "'";

                } else if ("org.joda.time.LocalDateTime".equals(name)) {
                    item.value = "'" + ((LocalDateTime) object).toString("yyyy-MM-dd HH:mm:ss") + "'";

                } else {
                    item.value = "null";
                }

                list.add(item);

            } catch (IllegalAccessException e) {
                Log.e(TAG, "toInsertSql: ", e);
                throw new RuntimeException(e);
            }
        }

        StringBuilder keySql = new StringBuilder();
        StringBuilder valueSql = new StringBuilder();

        for (int i = 0; i < list.size(); i++) {
            Item item = list.get(i);

            keySql.append(item.key);
            valueSql.append(item.value);

            if (i < list.size() - 1) {
                keySql.append(", ");
                valueSql.append(", ");
            }
        }

        //noinspection StringBufferReplaceableByString
        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO ").append(tableNameString).append(" (").append(keySql.toString()).append(") ");
        sql.append("VALUES ( ").append(valueSql.toString()).append(" )|");

        return sql.toString();
    }

    /**
     * 生成 UPDATE SQL
     *
     * @param t
     * @param whereSql
     * @param <T>
     * @return UPDATE SQL
     */
    public static <T> String toUpdateSql(T t, @NonNull String whereSql) {
        if (TextUtils.isEmpty(whereSql)) {
            throw new RuntimeException("whereSql 不能为空");
        }

        Class<?> cls = t.getClass();

        // 提取 TableName
        TableName tableName = t.getClass().getAnnotation(TableName.class);
        String tableNameString;
        if (tableName != null) {
            tableNameString = tableName.name();
        } else {
            tableNameString = cls.getSimpleName();
        }

        // 提取 UpdateField
        List<Field> updateFieldList = new ArrayList<>();
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field f : fields) {
            Annotation[] annotations = f.getDeclaredAnnotations();
            for (Annotation a : annotations) {
                if (a.annotationType() == UpdateField.class) {
                    updateFieldList.add(f);
                    break;
                }
            }
        }

        List<Item> list = new ArrayList<>();

        for (int i = 0; i < updateFieldList.size(); i++) {
            Field field = updateFieldList.get(i);
            field.setAccessible(true);

            String name = field.getType().getName();

            try {
                Object object = field.get(t);

                if (object != null) {
                    Item item = new Item();
                    item.key = getColumnName(field);

                    if ("java.lang.Float".equals(name)
                            || "java.lang.Integer".equals(name)) {
                        item.value = object.toString();
                        list.add(item);

                    } else if ("java.lang.String".equals(name)) {
                        item.value = "'" + object.toString() + "'";
                        list.add(item);

                    } else if ("org.joda.time.LocalDateTime".equals(name)) {
                        item.value = "'" + ((LocalDateTime) object).toString("yyyy-MM-dd HH:mm:ss") + "'";
                        list.add(item);

                    }
                }

            } catch (IllegalAccessException e) {
                Log.e(TAG, "toUpdateSql: ", e);
                throw new RuntimeException(e);
            }
        }

        //noinspection StringBufferReplaceableByString
        StringBuilder sql = new StringBuilder();
        sql.append("UPDATE ").append(tableNameString);

        for (int i = 0; i < list.size(); i++) {
            Item item = list.get(i);

            if (i == 0) {
                sql.append(" SET ");
            }

            sql.append(item.key).append(" = ").append(item.value);

            if (i < list.size() - 1) {
                sql.append(", ");
            }
        }
        sql.append(" WHERE ").append(whereSql).append("|");

        return sql.toString();
    }

    private static String getColumnName(Field field) {
        ColumnName columnName = field.getAnnotation(ColumnName.class);
        if (columnName != null) {
            return columnName.name();
        } else {
            return field.getName();
        }
    }

    private static class Item {
        String key;
        String value;
    }
}
